﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerContra : Player
{

    [System.Serializable]
    public class BulletPositionPair
    {
        public Vector2 Position = Vector2.zero;

        public Vector2 Direction = Vector2.right;
        public Vector2 TargetPosition = Vector2.positiveInfinity;

        public float Angle = 0f;

        public override string ToString()
        {
            return string.Format("Position:{0:G},TargetPosition:{1:G},Direction:{2:G}", Position, TargetPosition, Direction);
        }
    }


    [Header("基础配置")]
    [Tooltip("比尔还是兰斯")]
    private PlayerContext.EnumPlayer playerIdentity = PlayerContext.EnumPlayer.LanceBean;
    [Tooltip("组件-动画")]
    private Animator animator;
    [Tooltip("组件-玩家刚体")]
    private Rigidbody2D rig;
    [Tooltip("对象-上半身")]
    private GameObject upperBody;
    [Tooltip("对象-下半身")]
    private GameObject lowerBody;
    [Tooltip("对象-翻滚")]
    private GameObject rollBody;
    [Tooltip("对象-下落")]
    private GameObject fallBody;
    [Tooltip("对象-趴下")]
    private GameObject prostrateBody;
    [Tooltip("对象-下水")]
    private GameObject inWaterBody;
    [Tooltip("对象-波纹")]
    private GameObject rippleBody;
    [Tooltip("对象-死亡")]
    private GameObject diedBody;
    [Tooltip("对象-向前")]
    private GameObject forwardBody;
    [Tooltip("对象-向前-趴下")]
    private GameObject forwardProstrateBody;
    [Tooltip("对象-电击")]
    private GameObject electricShockBody;
    [Tooltip("对象-向前-跑")]
    private GameObject goAheadBody;
    [Tooltip("对象-3D-站立时脚底触发器")]
    private GameObject footTriggerBody;

    [Tooltip("对象-地面检查器")]
    private Transform groundCheck;

    [Header("音效配置")]
    public AudioSource footstepsSound;
    public AudioSource electricShockSound;

    [Header("角色参数")]
    [Tooltip("角色所受重力")]
    public float jumpGravity = 3f;
    [Tooltip("跳跃力量")]
    public float jumpForce = 15f;
    [Tooltip("角色移动速度")]
    // 30帧移动了30像素，帧率60->60像素/秒->3.75单位/秒
    public float speed = 3.75f;
    [Tooltip("角色面向的方向")]
    private bool running = false;
    [Tooltip("上一次开枪时间")]
    private float lastFireTime;
    [Tooltip("开枪间隔时间")]
    public float fireInterval = 0.1f;
    [Tooltip("举枪动作的持续时间，比开枪间隔稍长，如果持续开枪则使用举枪")]
    public float raisedGunKeepTime = 0.4f;
    [Tooltip("状态机")]
    private readonly StateMachine<PlayerContext.EnumState> stateMachine = new();
    [Tooltip("当前是否触达水面")]
    private bool inWater = false;
    [Tooltip("某些动作或状态回导致角色僵直")]
    private bool daze = false;


    [Header("动作参数")]
    [Tooltip("上岸动作配置")]
    public SpriteSequence goAshoreSequence;
    [Tooltip("落水水花动作")]
    public SeqAction splashAction = new() { beginWaitTime = 0f, intervalTime = 0f, keepingTime = 10f / 25f };
    public Sprite splashSprite;


    [Header("操作参数")]
    [Tooltip("操作左右")]
    private float axisX;
    [Tooltip("操作上下")]
    private float axisY;
    [Tooltip("连续按键开火")]
    private bool firePress;
    [Tooltip("单发按键开火")]
    private bool firePressDown;
    [Tooltip("跳跃按键")]
    private bool jumpPressDown;
    [Tooltip("用于不同角色的按键映射")]
    private Dictionary<KeyMapKey, string> keyMap;
    [Tooltip("角色移动方向")]
    private Vector2 move;

    [Header("碰撞配置")]
    [Tooltip("跳台层")]
    public LayerMask groundLayer;
    [Tooltip("水面层")]
    public LayerMask waterLayer;
    [Tooltip("墙体")]
    public LayerMask wallLayer;


    [Header("水中效果配置")]

    [Header("死亡效果配置")]
    [Tooltip("死亡翻滚素材")]
    public Sprite diedRollSprite;
    [Tooltip("死亡翻滚时间")]
    public float diedRollTime = 1f;
    [Tooltip("死亡平躺素材")]
    public Sprite diedLieDownSprite;
    [Tooltip("死亡平躺时间")]
    public float diedLieDownTime = 1f;

    [Header("重生配置")]
    [Tooltip("重生的位置")]
    public Vector2 rebornPosition = new Vector2();
    [Tooltip("重生的时间")]
    private float rebornTime;
    [Tooltip("重生后隐身的时间")]
    public float invisibleTime = 2f;
    [Tooltip("隐身闪烁间隔时间")]
    public float twinkleTime = 0.03f;
    [Tooltip("死亡动作")]
    private SeqAction dieAction = new() { };

    [Header("过关配置")]
    [Tooltip("剧本")]
    private Scenario scenario = Scenario.None;

    [Header("无敌配置")]
    private SeqAction godAction = new() { beginWaitTime = 0f, intervalTime = 0.1f, keepingTime = 10f };

    [Header("电击配置")]
    private SeqAction electricShockAction = new() { beginWaitTime = 0f, intervalTime = 0.1f, keepingTime = 1f };

    [Header("材质")]
    [Tooltip("比尔颜色的贴图材质")]
    private Material billColorMaterial;
    [Tooltip("兰斯颜色的贴图材质")]
    private Material lanceColorMaterial;

    [Header("调试")]
    [Tooltip("调试开关")]
    public bool debug = false;


    private Material[] mats;
    private Sprite[] goAheadSprites;
    private SeqAction goAheadAction = new() { };


    private ScenarioDelegate scenarioDelegate;

    [Tooltip("比尔还是兰斯")]
    public override PlayerContext.EnumPlayer PlayerIdentity
    {
        get
        {
            return playerIdentity;
        }
        set
        {
            playerIdentity = value;
            ChangePlayerIdentity();
        }
    }
    private void Awake()
    {
        //初始化角色的颜色贴图
        billColorMaterial = GetComponent<SpriteRenderer>().material;
        lanceColorMaterial = Resources.Load<Material>("Materials/魂_兰斯的颜色");
        mats = new Material[] { billColorMaterial, lanceColorMaterial };


        //加载玩家角色子弹
        Resources.LoadAll<ABullet>("Prefabs").Action((ABullet a) =>
        {
            if (a.playerBullet)
            {
                if (!dictBulletType.ContainsKey(a.type))
                {
                    dictBulletType.Add(a.type, a.gameObject);
                }
            }
        });

        //初始化状态机
        stateMachine.Registe(this);
        playerState = PlayerContext.EnumState.None;

        //初始化组件对象
        animator = GetComponent<Animator>();
        rig = GetComponent<Rigidbody2D>();
        rig.gravityScale = jumpGravity;
        if (followCamera == null)
        {
            followCamera = Camera.main;
        }
        cameraLevel = followCamera.GetComponent<CameraLevel>();
        camera3DLevel = followCamera.GetComponent<Camera3DLevel>();

        //初始化身体部分对象
        upperBody = transform.Find("a_上半身").gameObject;
        lowerBody = transform.Find("a_下半身").gameObject;
        rollBody = transform.Find("a_翻滚").gameObject;
        fallBody = transform.Find("a_下落").gameObject;
        prostrateBody = transform.Find("a_趴下").gameObject;
        inWaterBody = transform.Find("a_落水").gameObject;
        rippleBody = transform.Find("波纹").gameObject;
        diedBody = transform.Find("a_死亡").gameObject;
        forwardBody = transform.Find("3D").Find("向前").gameObject;
        forwardProstrateBody = transform.Find("3D").Find("向前_趴下").gameObject;
        electricShockBody = transform.Find("3D").Find("电击").gameObject;
        goAheadBody = transform.Find("3D").Find("向前_跑").gameObject;
        footTriggerBody = transform.Find("3D").Find("站立时脚底触发器").gameObject;
        groundCheck = transform.Find("地面检查器");
        footstepsSound = transform.Find("脚步音效").GetComponent<AudioSource>();
        electricShockSound = transform.Find("电击音效").GetComponent<AudioSource>();

        lookAt = new Vector2(1f, 0f);

        animator.SetBool("3D", Is3DLevel() && !Is3DBossLevel());

        goAheadSprites = new Sprite[]{
            ResourcesPool.Sprites["魂_向前_跑1"],
            ResourcesPool.Sprites["魂_向前_跑2"],
        };
    }

    void Start()
    {
        ChangePlayerIdentity();

        Run();
        Reborn(playerState, out playerState);
        // godAction.ReStart();
        godAction.done = true;
    }

    private void Update()
    {
        if (daze)
        {
            move.Set(0f, 0f);
            jumpPressDown = firePressDown = firePress = false;
            return;
        }

        //取得场景的剧本状态，如果处于某个剧本则根据剧本决定行动，否则根据按键决定行动
        ScenarioAction scenarioAction = UpdateScenario();
        if (scenarioAction == null)
        {
            scenarioAction = new ScenarioAction();
        }
        axisX = scenarioAction.GetFloat(KeyMapKey.Horizontal.ToString(), Input.GetAxisRaw(keyMap.GetValueOrDefault(KeyMapKey.Horizontal)));
        axisY = scenarioAction.GetFloat(KeyMapKey.Vertical.ToString(), Input.GetAxisRaw(keyMap.GetValueOrDefault(KeyMapKey.Vertical)));
        //如果按键尚未在FixUpdate中处理则保持按键状态
        firePress = firePress || scenarioAction.GetBool(KeyMapKey.Fire.ToString(), Input.GetButton(keyMap.GetValueOrDefault(KeyMapKey.Fire)));
        firePressDown = firePressDown || scenarioAction.GetBool(KeyMapKey.Fire.ToString(), Input.GetButtonDown(keyMap.GetValueOrDefault(KeyMapKey.Fire)));
        jumpPressDown = jumpPressDown || scenarioAction.GetBool(KeyMapKey.Jump.ToString(), Input.GetButtonDown(keyMap.GetValueOrDefault(KeyMapKey.Jump)));

        //判断当前是否可以开枪，是否连发
        firePressDown = (bulletType == ABullet.BulletType.M) ? firePress : firePressDown;

        //如果被电击则不能开枪和跳跃
        if (playerState == PlayerContext.EnumState.ElectricShock)
        {
            firePress = jumpPressDown = false;
            axisX = 0f;
        }
        //在伪3D场景中向前跑的时候不改变左右方向
        //根据输入判断朝向
        keyDir.x = Mathf.Approximately(axisX, 0.0f) ? 0f : (axisX > 0.0f ? 1 : -1);
        //如果左右按键没有按下则保持上一次的朝向
        lookAt.x = keyDir.x == 0 ? lookAt.x : keyDir.x;
        if (keyDir.x == 0f)
        {
            //跳起、落下时保持移动
            if (playerState != PlayerContext.EnumState.Roll && playerState != PlayerContext.EnumState.Fall)
            {
                move.x = keyDir.x;
            }
        }
        else
        {
            move.x = keyDir.x;
        }

        keyDir.y = Mathf.Approximately(axisY, 0.0f) ? 0 : (axisY > 0.0f ? 1 : -1);
        lookAt.y = keyDir.y;
        move.y = lookAt.y;


    }

    private void FixedUpdate()
    {
        UpdateAnimatorAndSound();
        //判断站在地面还是水面
        onGround = CheckGround();
        if (onGround)
        {
            inWater = false;
        }
        else
        {
            inWater = Physics2D.Raycast(groundCheck.position, Vector2.down, 0.1f, waterLayer);
        }

        //调用状态机
        stateMachine.Invoke(playerState, out playerState, (bool stateChange, PlayerContext.EnumState inState, out PlayerContext.EnumState outState) =>
        {
            //DefaultUpdateAction
            outState = inState;

        }, (PlayerContext.EnumState inState) =>
        {
            //PreUpdateAction
            daze = false;
            rig.velocity = new(move.x * speed, rig.velocity.y);

        }, (bool stateChange, PlayerContext.EnumState inState, PlayerContext.EnumState outState) =>
        {
            //PostUpdateAction
            if (outState != PlayerContext.EnumState.GoingAshore)
            {
                ChangePosture(outState);
            }
        });


        UpdateInvisible();
        UpdateGod();
        UpdateInViewport();
        //根据lookAt设置面朝方向
        transform.localScale = new Vector3(Mathf.Abs(transform.localScale.x) * lookAt.x, transform.localScale.y, transform.localScale.z);

        if (firePressDown)
        {
            if (Time.time - lastFireTime > fireInterval)
            {
                Fire();
                lastFireTime = Time.time;
            }
            firePressDown = firePress = false;

        }

        jumpPressDown = false;

    }

    // *↓↓↓↓↓↓↓↓↓↓↓↓↓↓以下是状态机的状态处理方法↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    private void UpdateStateNone(bool stateChanged, PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = PlayerContext.EnumState.Land;
    }

    private void UpdateStateLand(bool stateChanged, PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;

        if (jumpPressDown)
        {
            rig.velocity += Vector2.up * jumpForce;
            outState = PlayerContext.EnumState.Roll;
        }
        else if (onGround && keyDir.x == 0f && keyDir.y == -1f && !Is3DBossLevel())
        {
            outState = PlayerContext.EnumState.Prostrate;
        }
        else if (!onGround)
        {
            outState = PlayerContext.EnumState.Fall;
        }
        else if (Is3DLevel())
        {
            //在伪3D模式的关卡里，不移动的时候进入Idle状态
            if (keyDir.x == 0f)
            {
                outState = PlayerContext.EnumState.Idle;
            }
            else if (keyDir.y == 1f && !Is3DBossLevel())
            {
                if (cameraLevel.HasElectricField())
                {
                    outState = PlayerContext.EnumState.ElectricShock;
                }
                else if (keyDir.x == 0f)
                {
                    goAheadAction.ReStart();
                    outState = PlayerContext.EnumState.GoAhead;
                }

            }
        }

        //在伪3D场景中上半身不进行碰撞检测
        if (upperBody.TryGetComponent(out Collider2D collider))
        {
            collider.enabled = !Is3DLevel() || Is3DBossLevel();
        }
    }
    private void UpdateStateRoll(bool stateChanged, PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;
        if ((onGround && Mathf.Abs(rig.velocity.y) < 0.001f))
        {
            outState = PlayerContext.EnumState.Land;
        }
        else if (inWater)
        {
            outState = PlayerContext.EnumState.Splash;
        }

        //在伪3D场景中跳跃时不进行碰撞拣择
        if (rollBody.TryGetComponent(out Collider2D collider))
        {
            collider.enabled = !Is3DLevel() || Is3DBossLevel();
        }

    }
    private void UpdateStateFall(bool stateChanged, PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;
        if ((onGround && Mathf.Abs(rig.velocity.y) < 0.001f))
        {
            outState = PlayerContext.EnumState.Land;
        }
        else if (inWater)
        {
            outState = PlayerContext.EnumState.Splash;
        }
    }
    private void UpdateStateSplash(bool stateChanged, PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;
        daze = true;
        if (stateChanged)
        {
            splashAction.ReStart();
        }
        splashAction.Update((SeqAction seq) =>
        {
            animator.enabled = false;
            if (inWaterBody.TryGetComponent(out SpriteRenderer sr))
            {
                sr.sprite = splashSprite;
            }
        });
        if (splashAction.done)
        {
            animator.enabled = true;
            outState = PlayerContext.EnumState.FallInWater;
        }
    }
    private void UpdateStateFallInWater(bool stateChanged, PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;
        if (keyDir.x == 0f && keyDir.y == -1f)
        {
            outState = PlayerContext.EnumState.HideInWater;
        }
    }
    private void UpdateStateHideInWater(bool stateChanged, PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;
        if (keyDir.y != -1f)
        {
            outState = PlayerContext.EnumState.FallInWater;
        }
        rig.velocity = Vector2.zero;

    }
    private void UpdateStateProstrate(bool stateChanged, PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;
        if (onGround && (keyDir.x != 0f || keyDir.y != -1f))
        {
            outState = PlayerContext.EnumState.Land;
        }
        else if (!onGround)
        {
            outState = PlayerContext.EnumState.Fall;
        }
        else if (jumpPressDown && Is3DLevel())
        {
            rig.velocity += Vector2.up * jumpForce;
            outState = PlayerContext.EnumState.Roll;
        }
        else if (jumpPressDown)
        {
            Vector3 cameraBottom = followCamera.ViewportToWorldPoint(Vector3.zero);
            Vector3 footPoint = GetBodyPartPosition(Person.BodyPart.Foot);
            footPoint.y -= 1;
            RaycastHit2D hit = Physics2D.Raycast(footPoint, Vector2.down, followCamera.orthographicSize * 2, groundLayer | waterLayer);
            if (hit && hit.point.y > cameraBottom.y)
            {
                Vector2 pos = rig.transform.position;
                pos.y -= 0.8f;
                rig.transform.position = pos;
                outState = PlayerContext.EnumState.Fall;
            }

        }
    }

    private void UpdateStateGoingAshore(bool changeState, PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;
        daze = true;

        animator.enabled = false;
        rig.gravityScale = 0;
        rig.velocity = Vector2.zero;

        if (!goAshoreSequence.Update(gameObject, new Vector3(lookAt.x, 1, 1)))
        {
            animator.enabled = true;
            rig.gravityScale = jumpGravity;
            outState = PlayerContext.EnumState.Fall;
        }
    }

    private void UpdateStateDie(bool stateChanged, PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;
        daze = true;
        bool needReborn = false;
        dieAction.Update((SeqAction seq) =>
        {
            if (seq.IsFirstAction())
            {
                Constant.Sounds.PlayerDeath.PlayOneShot();
            }

            float radius = 2.0f;
            if (seq.DurationTime <= diedRollTime)
            {
                //自身旋转
                float angle = seq.DurationTime / diedRollTime * 360;
                diedBody.transform.localRotation = Quaternion.AngleAxis(angle, Vector3.forward);

                //向后圆弧位移
                angle = seq.DurationTime / diedRollTime * 180;
                float offsetX = Mathf.Cos(angle * Mathf.PI / 180) * radius;
                float offsetY = Mathf.Sin(angle * Mathf.PI / 180) * radius;
                float x = offsetX - radius;
                float y = offsetY + 0.5f;
                diedBody.transform.localPosition = new Vector3(x, y, diedBody.transform.localPosition.z);
                if (angle < 150f)
                {
                    diedBody.GetComponent<SpriteRenderer>().sprite = diedRollSprite;
                }
                else
                {
                    diedBody.GetComponent<SpriteRenderer>().sprite = diedLieDownSprite;
                }

            }
            else
            {
                float lieDownDt = seq.DurationTime - diedRollTime;
                float x = -radius * 2, y = 0.0f;
                diedBody.transform.localRotation = Quaternion.AngleAxis(0, Vector3.forward);
                diedBody.transform.localPosition = new Vector3(x, y, diedBody.transform.localPosition.z);
                diedBody.GetComponent<SpriteRenderer>().sprite = diedLieDownSprite;
                if (lieDownDt > diedLieDownTime)
                {
                    needReborn = true;
                }
            }
        });

        if (needReborn)
        {
            Reborn(inState, out outState);
        }

    }
    private void UpdateStateIdle(bool stateChanged, PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;
        if(forwardBody.TryGetComponent(out BoxCollider2D collider)){
            if(Is3DLevel() && !Is3DBossLevel()){
                collider.offset=new Vector2(0f,0.3f);
                collider.size=new Vector2(1f,1f);
            }else{
                collider.offset=new Vector2(0f,1f);
                collider.size=new Vector2(1f,2f);
            }
        }
        if(!Is3DLevel()){
            outState = PlayerContext.EnumState.Land;
        }else if (keyDir.x != 0f)
        {
            outState = PlayerContext.EnumState.Land;
        }
        else if (keyDir.y == 1f && !Is3DBossLevel())
        {
            if (cameraLevel.HasElectricField())
            {
                outState = PlayerContext.EnumState.ElectricShock;
            }
            else
            {
                goAheadAction.ReStart();
                outState = PlayerContext.EnumState.GoAhead;
            }
        }
        else if (jumpPressDown)
        {
            rig.velocity += Vector2.up * jumpForce;
            outState = PlayerContext.EnumState.Roll;
        }
        else if (keyDir.y == -1 && !Is3DBossLevel())
        {
            outState = PlayerContext.EnumState.Prostrate;
        }
    }

    private void UpdateStateElectricShock(bool stateChanged, PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;
        if (stateChanged)
        {
            electricShockAction.ReStart();
        }
        bool keepShock = keyDir.y == 1f && cameraLevel.HasElectricField();
        if (keepShock)
        {
            // outState = PlayerContext.EnumState.GoAhead;
        }
        else if (keyDir.y == 0f)
        {
            // outState = PlayerContext.EnumState.Land;
        }
        else if (keyDir.y == -1)
        {
            // outState = PlayerContext.EnumState.Prostrate;
        }

        daze = false;
        rig.velocity = Vector2.zero;
        if (!electricShockSound.isPlaying)
        {
            electricShockSound.loop = true;
            electricShockSound.Play();
        }

        PlayerContext.EnumState tempState = PlayerContext.EnumState.None;
        electricShockAction.Update(
            (SeqAction seq) =>
            {
                int index = seq.seqNo % mats.Length;
                Material mat = mats[index];
                ChangePlayerColor(mat);
                if (keepShock && seq.DurationTime >= seq.keepingTime)
                {
                    seq.ReStart();
                }
            },
            (SeqAction seq) =>
            {
                if (keyDir.y == 0f)
                {
                    tempState = PlayerContext.EnumState.Land;
                }
                else if (keyDir.y == -1)
                {
                    tempState = PlayerContext.EnumState.Prostrate;
                }
                else if (keyDir.y == 1f && !cameraLevel.HasElectricField())
                {
                    goAheadAction.ReStart();
                    tempState = PlayerContext.EnumState.GoAhead;
                }

            }
        );
        if (tempState != PlayerContext.EnumState.None)
        {
            outState = tempState;
        }

        if (!inState.Equals(outState))
        {
            ChangeToDefaultColor();
            if (electricShockSound.isPlaying)
            {
                electricShockSound.Stop();
            }
        }

    }

    private void UpdateStateGoAhead(bool stateChanged, PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;
        rig.velocity = Vector2.zero;
        Vector2 donePosition = Vector2.zero;
        goAheadAction.Update((SeqAction seq) =>
        {
            if (seq.IsFirstAction())
            {
                Vector2 oriPosition = transform.position;
                Vector2 dir = Transform3DPositionWithState(oriPosition, playerState) - oriPosition;
                Ray2D ray = new(Vector2.zero, dir);
                seq.PropertyVector.Add("targetPosition", ray.GetPoint(1.75f));
                seq.PropertyFloat.Add("lookAt.x", lookAt.x);

            }
            Vector2 targetPosition = seq.PropertyVector["targetPosition"];
            int index = Mathf.FloorToInt(seq.DurationTime / (11f / 60f)) % goAheadSprites.Length;// seq.seqNo % goAheadSprites.Length;
            if (goAheadBody.TryGetComponent(out SpriteRenderer sr))
            {
                sr.sprite = goAheadSprites[index];
            }
            lookAt.x = seq.PropertyFloat["lookAt.x"];
            Vector2 position = goAheadBody.transform.localPosition;
            float sec = 1f;
            Vector2 speed = targetPosition / sec;
            speed.x *= lookAt.x;
            position += speed * seq.DeltaTime;
            // donePosition=position;
            if (seq.DurationTime >= sec)
            {
                seq.done = true;
                position = Vector2.zero;
            }
            donePosition = goAheadBody.transform.position;
            goAheadBody.transform.localPosition = position;

        });

        if (goAheadAction.done)
        {
            bool endOfPassageway = false;
            if (cameraLevel is Camera3DLevel)
            {
                endOfPassageway = ((Camera3DLevel)cameraLevel).NextPassageway();
            }
            if (endOfPassageway)
            {
                // Vector2 position=transform.position;
                // position+=donePosition;
                transform.position = donePosition;
                rig.velocity += Vector2.up * jumpForce;
                outState = PlayerContext.EnumState.Roll;
            }
            else if (keyDir.y == 1f && keyDir.x == 0f && !cameraLevel.HasElectricField())
            {
                goAheadAction.ReStart();
                outState = PlayerContext.EnumState.GoAhead;
            }
            else if (keyDir.x != 0f || keyDir.y == 0f)
            {
                outState = PlayerContext.EnumState.Land;
            }
            else if (keyDir.y == -1)
            {
                outState = PlayerContext.EnumState.Prostrate;
            }
        }
    }

    // *↑↑↑↑↑↑↑↑↑↑↑↑↑↑以上是状态机的状态处理方法↑↑↑↑↑↑↑↑↑↑↑↑↑↑
    private void ChangePlayerIdentity()
    {
        keyMap = new Dictionary<KeyMapKey, string>();
        if (playerIdentity == PlayerContext.EnumPlayer.BillRizer)
        {
            keyMap.Add(KeyMapKey.Horizontal, "Player1 Horizontal");
            keyMap.Add(KeyMapKey.Vertical, "Player1 Vertical");
            keyMap.Add(KeyMapKey.Fire, "Player1 Fire");
            keyMap.Add(KeyMapKey.Jump, "Player1 Jump");
            ChangePlayerColor(billColorMaterial);
            rebornPosition = new Vector2(0.1875f, 0.8666667f);
            gameObject.name = "比尔";
        }
        else if (playerIdentity == PlayerContext.EnumPlayer.LanceBean)
        {
            keyMap.Add(KeyMapKey.Horizontal, "Player2 Horizontal");
            keyMap.Add(KeyMapKey.Vertical, "Player2 Vertical");
            keyMap.Add(KeyMapKey.Fire, "Player2 Fire");
            keyMap.Add(KeyMapKey.Jump, "Player2 Jump");
            ChangePlayerColor(lanceColorMaterial);
            rebornPosition = new Vector2(0.3125f, 0.8666667f);
            gameObject.name = "兰斯";
        }
    }

    private void ChangePlayerColor(Material material)
    {
        Transform[] changeColorPart = new Transform[] {
            upperBody.transform,
            lowerBody.transform,
            rollBody.transform,
            fallBody.transform,
            prostrateBody.transform,
            inWaterBody.transform,
            diedBody.transform,
            forwardBody.transform,
            forwardProstrateBody.transform,
            electricShockBody.transform,
            goAheadBody.transform,
        };
        foreach (Transform part in changeColorPart)
        {
            if (part.TryGetComponent(out SpriteRenderer partSr))
            {
                partSr.material = material;
            }
        }

    }

    public override int GetLife()
    {
        int life = 0;
        if (this.playerIdentity == PlayerContext.EnumPlayer.BillRizer)
        {
            life = ContraGlobal.Player1.Life;
        }
        else if (this.playerIdentity == PlayerContext.EnumPlayer.LanceBean)
        {
            life = ContraGlobal.Player2.Life;
        }
        life = Mathf.Clamp(life, 0, 100);
        return life;
    }

    public override void RunScenario(ScenarioDelegate scenarioDelegate){
        this.scenarioDelegate=scenarioDelegate;
    }    

    private ScenarioAction UpdateScenario()
    {
        ScenarioAction ret = null;
        if(this.scenarioDelegate!=null){
            ret=this.scenarioDelegate.Invoke(this);
        }
        return ret;
    }

    public override Vector2 GetBodyPartPosition(Person.BodyPart bodyPart)
    {
        Vector2 ret = default;
        switch (bodyPart)
        {
            case Person.BodyPart.Head:
                {
                    ret = transform.position + Vector3.up * 1.75f;
                    if (playerState == PlayerContext.EnumState.Prostrate)
                    {
                        ret = transform.position + Vector3.right * 0.625f * lookAt.x + Vector3.up * 0.5f;
                    }
                }
                break;
            case Person.BodyPart.Foot:
                {
                    Collider2D colliderFoot = transform.Find("地面检查器").GetComponent<Collider2D>();
                    Bounds bounds = colliderFoot.bounds;
                    ret = new(bounds.center.x, bounds.min.y);

                }
                break;
            default:
                ret = transform.position + Vector3.up * 1f;
                if (playerState == PlayerContext.EnumState.Prostrate)
                {
                    ret = transform.position;
                }
                break;

        }
        return ret;
    }

    private void ChangePosture(PlayerContext.EnumState state)
    {
        bool invisible = Time.time - rebornTime <= invisibleTime;
        List<GameObject> activeBodys = new();
        switch (state)
        {
            case PlayerContext.EnumState.Roll:
                activeBodys.Add(rollBody);
                break;
            case PlayerContext.EnumState.None:
            case PlayerContext.EnumState.Land:
                activeBodys.Add(upperBody);
                activeBodys.Add(lowerBody);
                if (Is3DLevel() && !Is3DBossLevel())
                {
                    activeBodys.Add(footTriggerBody);
                }
                break;
            case PlayerContext.EnumState.Fall:
                activeBodys.Add(fallBody);
                break;
            case PlayerContext.EnumState.Prostrate:
                if (CameraLevelType == CameraLevel.LevelType.Pseudo3D)
                {
                    activeBodys.Add(forwardProstrateBody);
                }
                else
                {
                    activeBodys.Add(prostrateBody);
                }
                break;
            case PlayerContext.EnumState.Splash:
                activeBodys.Add(inWaterBody);
                break;
            case PlayerContext.EnumState.FallInWater:
                activeBodys.Add(inWaterBody);
                activeBodys.Add(rippleBody);
                break;
            case PlayerContext.EnumState.HideInWater:
                activeBodys.Add(rippleBody);
                break;
            case PlayerContext.EnumState.GoingAshore:
                activeBodys.Add(inWaterBody);
                break;
            case PlayerContext.EnumState.Die:
                activeBodys.Add(diedBody);
                break;
            case PlayerContext.EnumState.Idle:
                activeBodys.Add(forwardBody);
                activeBodys.Add(footTriggerBody);
                break;
            case PlayerContext.EnumState.ElectricShock:
                activeBodys.Add(electricShockBody);
                break;
            case PlayerContext.EnumState.GoAhead:
                activeBodys.Add(goAheadBody);
                break;

        }
        new GameObject[] {
        upperBody,
        lowerBody,
        rollBody,
        fallBody,
        prostrateBody,
        inWaterBody,
        rippleBody,
        diedBody,
        forwardBody,
        forwardProstrateBody,
        electricShockBody,
        goAheadBody,
        footTriggerBody,
        }.Action((GameObject o) =>
        {
            if (activeBodys.IndexOf(o) >= 0)
            {
                o.SetActive(true);
                if (!invisible)
                {
                    if (o.TryGetComponent(out SpriteRenderer sr))
                    {
                        sr.maskInteraction = SpriteMaskInteraction.None;
                    }
                }
            }
            else
            {
                o.SetActive(false);
            }
        });

    }

    private bool CheckGround()
    {
        BoxCollider2D collider = groundCheck.gameObject.GetComponent<BoxCollider2D>();
        Bounds bounds = collider.bounds;
        Vector2 leftPoint = new Vector2(bounds.min.x, bounds.min.y);
        Vector2 rightPoint = new Vector2(bounds.max.x, bounds.min.y);
        bool leftIsGround = Physics2D.Raycast(leftPoint, Vector2.down, 0.2f, groundLayer);
        bool ret = leftIsGround;
        if (!ret)
        {
            bool rightIsGround = Physics2D.Raycast(rightPoint, Vector2.down, 0.2f, groundLayer);
            ret = rightIsGround;
        }
        // ret = ret && Mathf.Abs(rig.velocity.y) < 0.001;
        return ret;
    }


    //开枪
    private void Fire()
    {
        if (PlayerMuzzle.GetMuzzles(this,out PlayerMuzzle.Muzzle oriMuzzle,out PlayerMuzzle.Muzzle[] muzzles))
        {
            GameObject bulletFabs = dictBulletType.GetValueOrDefault(bulletType, null);
            if (bulletType == ABullet.BulletType.None)
            {
                bulletType = ABullet.BulletType.C;
            }
            if (bulletFabs != null)
            {
                if (ABullet.BulletType.L.Equals(bulletType))
                {
                    ABulletL.ClearExistBullet();
                }

                foreach (PlayerMuzzle.Muzzle muzzle in muzzles)
                {
                    Vector2 bulletPos = muzzle.firePosition;
                    Vector2 bulletDirection = muzzle.Direction;
                    Vector2 bulletTargetPos = muzzle.targetPosition;
                    float angle = muzzle.Angle;

                    GameObject objBullet = Instantiate(bulletFabs, bulletPos, Quaternion.identity);
                    if (playerState == PlayerContext.EnumState.Prostrate && Is3DLevel())
                    {
                        objBullet.layer = LayerMask.NameToLayer("子弹_贴地");
                    }
                    ABullet aBullet;
                    if (ABullet.BulletType.L.Equals(bulletType))
                    {
                        ABulletL bulletL = objBullet.GetComponent<ABulletL>();
                        bulletL.SetFirePosition(oriMuzzle.firePosition);
                        aBullet = bulletL;
                    }
                    else
                    {
                        aBullet = objBullet.GetComponent<ABullet>();
                    }
                    aBullet.SetBulletR(bulletR);
                    aBullet.transform.Rotate(0, 0, angle);
                    aBullet.SetSource(gameObject);
                    aBullet.SetBulletType(bulletType);
                    if (aBullet != null)
                    {
                        float speed = 0f;
                        if (Is3DLevel() && !Is3DBossLevel())
                        {
                            speed = Vector2.Distance(bulletPos, bulletTargetPos) / (22f / 60f);
                        }
                        if(!muzzle.targetLimit){
                            bulletTargetPos=Vector2.positiveInfinity;
                        }
                        aBullet.Launch(bulletDirection, bulletTargetPos, speed);
                        // aBullet.Launch(muzzle, speed);

                        Constant.StructSoundClip soundClip = null;
                        switch (bulletType)
                        {
                            case ABullet.BulletType.C:
                                soundClip = Constant.Sounds.PlayerBulletC;
                                break;
                            case ABullet.BulletType.M:
                                soundClip = Constant.Sounds.PlayerBulletM;
                                break;
                            case ABullet.BulletType.S:
                                soundClip = Constant.Sounds.PlayerBulletS;
                                break;
                            case ABullet.BulletType.F:
                                soundClip = Constant.Sounds.PlayerBulletF;
                                break;
                            case ABullet.BulletType.L:
                                soundClip = Constant.Sounds.PlayerBulletL;
                                break;
                        }
                        if (soundClip != null)
                        {
                            soundClip.PlayOneShot();
                        }
                    }
                }
                animator.SetTrigger("Fire");
            }
        }
    }

    /**
     * <summary>
     * * 触发上岸动作
     * * 此方法在AMoveFroundCheck中通过sendMessage调用
     * </summary>
     */
    private void GoAshore()
    {
        GoAshore(playerState, out playerState);
    }
    private void GoAshore(PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;
        if (inWater)
        {
            rig.velocity = Vector2.zero;
            outState = PlayerContext.EnumState.GoingAshore;
            goAshoreSequence.Restart();
            //ChangeBodyDisplay(PlayerContext.EnumState.GoingAshore);
        }

    }

    public void Run()
    {
        running = true;
    }
    public void Stop()
    {
        running = false;
    }

    public void Reborn(PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;
        if (!running) return;
        int life = GetLife();
        if (this.playerIdentity == PlayerContext.EnumPlayer.BillRizer)
        {
            UILifeBar.BillInstance.SetLife(life);
        }
        else if (this.playerIdentity == PlayerContext.EnumPlayer.LanceBean)
        {
            UILifeBar.LanceInstance.SetLife(life);
        }
        if (life > 0)
        {
            rebornTime = Time.time;
            rig.velocity = Vector2.zero;
            rig.gravityScale = jumpGravity;
            Vector2 position = followCamera.ViewportToWorldPoint(rebornPosition);
            transform.position = position;
            outState = PlayerContext.EnumState.Roll;
        }
        else
        {
            if (followCamera.TryGetComponent(out CameraLevel cameraLevel))
            {
                cameraLevel.GameOver(PlayerIdentity);
            }
        }
    }
    private bool CheckAtViewportBotom()
    {
        //这里不适用collider.bounds,因为当position改变后，bounds不会立即改变。导致Reborn中已经修改了position，但bounds仍然判定为屏幕底部
        Collider2D collider = transform.Find("地面检查器").GetComponent<Collider2D>();
        float bottomY = collider.transform.position.y - collider.bounds.extents.y;
        Vector3 viewportBottom = Camera.main.ViewportToWorldPoint(Vector3.zero);

        if (viewportBottom.y >= bottomY)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public override void BodyPartCollision(GameObject targetGameObject)
    {
        try
        {
            if ((new List<string>() { "敌人", "敌人子弹", "敌人3D滚地", "子弹_爆" }).IndexOf(LayerMask.LayerToName(targetGameObject.layer)) >= 0)
            {
                Die();
            }
            else if ((new List<string>() { "物品" }).IndexOf(LayerMask.LayerToName(targetGameObject.layer)) >= 0)
            {
                Gun gun = targetGameObject.GetComponent<Gun>();
                if (gun != null)
                {
                    if (gun.bulletType == ABullet.BulletType.R)
                    {
                        bulletR = true;
                    }
                    else
                    {
                        this.bulletType = gun.bulletType;
                    }
                    gun.PickUp();
                }
            }
        }
        catch (NullReferenceException e)
        {
            Debug.LogError(e);
        }
    }

    public void Die()
    {
        if (godAction.done)
        {
            Die(false);
        }
    }
    public void Die(bool compel)
    {
        Die(compel, playerState, out playerState);
    }
    private void Die(bool compel, PlayerContext.EnumState inState, out PlayerContext.EnumState outState)
    {
        outState = inState;
        // return;
        if (!running)
        {
            return;
        }
        if (inState != PlayerContext.EnumState.Die && (Time.time - rebornTime > invisibleTime || compel))
        {
            ChangeToDefaultColor();
            if (electricShockSound.isPlaying)
            {
                electricShockSound.Stop();
            }

            outState = PlayerContext.EnumState.Die;
            dieAction.ReStart();
            rig.velocity = Vector2.zero;
            rig.gravityScale = 0;
            diedBody.transform.localPosition = new Vector3(0f, 0.5f, 0f);
            diedBody.transform.localRotation = Quaternion.AngleAxis(0, Vector3.forward);
            if (playerIdentity == PlayerContext.EnumPlayer.BillRizer)
            {
                ContraGlobal.Player1.Life--;
            }
            else if (playerIdentity == PlayerContext.EnumPlayer.LanceBean)
            {
                ContraGlobal.Player2.Life--;
            }
        }
    }

    private void UpdateInvisible()
    {
        float dt = Time.time - rebornTime;
        if (dt <= invisibleTime)
        {
            int twinkleValue = Mathf.FloorToInt(dt / twinkleTime) % 2;
            SpriteMaskInteraction value = twinkleValue == 0 ? SpriteMaskInteraction.None : SpriteMaskInteraction.VisibleInsideMask;
            foreach (SpriteRenderer sr in transform.GetComponentsInChildren<SpriteRenderer>())
            {
                sr.maskInteraction = value;
            }
        }
        else
        {
            if (dt <= invisibleTime + 1f)
            {
                foreach (SpriteRenderer sr in transform.GetComponentsInChildren<SpriteRenderer>())
                {
                    sr.maskInteraction = SpriteMaskInteraction.None;
                }
            }
        }
    }


    private void UpdateGod()
    {
        if (!godAction.done)
        {
            godAction.Update(
                (SeqAction seq) =>
            {
                int index = seq.seqNo % mats.Length;
                ChangePlayerColor(mats[index]);
            },
            (SeqAction seq) =>
            {
                ChangeToDefaultColor();
            });
        }
    }

    private void UpdateInViewport()
    {
        if(scenarioDelegate!=null){
            return;
        }
        //如果角色处于剧情模式则不限制边界，落下也不会死
        if (CheckAtViewportBotom() && scenarioDelegate==null)
        {
            Die(true);
        }

        float left = followCamera.ViewportToWorldPoint(Vector3.zero).x + 1.5f;
        float right = followCamera.ViewportToWorldPoint(Vector3.right).x - 1.5f;
        Vector3 position = transform.position;

        //不允许人物移动超出摄像头的左右边界
        if (position.x < left)
        {
            position.x = left;
        }
        if (scenario == Scenario.None)
        {
            if (position.x > right)
            {
                position.x = right;
            }

        }
        transform.position = position;
    }


    private Vector2 Transform3DPositionWithState(Vector2 startPosition, PlayerContext.EnumState state)
    {

        Rect startRect = camera3DLevel.GetPlayerViewRect();
        Rect targetRect = camera3DLevel.GetEnemyViewRect();
        if (state == PlayerContext.EnumState.Prostrate)
        {
            startRect = camera3DLevel.GetPlayerProstrateViewRect();
        }
        return Utility.Transform3DPosition(startPosition, startRect, targetRect);

    }

    private void UpdateAnimatorAndSound()
    {
        //设置动画参数
        float moveSpeed = Mathf.Abs(move.x);
        animator.SetFloat("Speed", moveSpeed);
        animator.SetFloat("LookAtRight", lookAt.x);
        animator.SetFloat("LookAtUp", lookAt.y);
        animator.SetFloat("MoveRight", move.x);
        animator.SetFloat("MoveUp", move.y);
        animator.SetBool("FireAction", firePressDown || (Time.time - lastFireTime < raisedGunKeepTime));
        animator.SetBool("3D", Is3DLevel() && !Is3DBossLevel());

        //音效
        if (moveSpeed != 0 && playerState == PlayerContext.EnumState.Land)
        {
            if (!footstepsSound.isPlaying)
            {
                footstepsSound.loop = true;
                footstepsSound.Play();
            }
        }
        else
        {
            footstepsSound.Stop();
        }
    }

    private void ChangeToDefaultColor()
    {
        if (playerIdentity == PlayerContext.EnumPlayer.BillRizer)
        {
            ChangePlayerColor(billColorMaterial);
        }
        else
        {
            ChangePlayerColor(lanceColorMaterial);
        }
    }

    // *↓↓↓↓↓↓↓↓↓↓↓↓↓↓以下是实现PlayerContext的方法↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    public override Vector2 UpperBodyOffset(){
        return upperBody.transform.localPosition;
    }
    public override Vector2 LowerBodyOffset(){
        return lowerBody.transform.localPosition;

    }
    public override Vector2 RollBodyOffset(){
        return rollBody.transform.localPosition;

    }
    public override Vector2 FallBodyOffset(){
        return fallBody.transform.localPosition;

    }
    public override Vector2 ProstrateBodyOffset(){
        return prostrateBody.transform.localPosition;

    }
    public override Vector2 InWaterBodyOffset(){
        return inWaterBody.transform.localPosition;

    }
    public override Vector2 RippleBodyOffset(){
        return rippleBody.transform.localPosition;

    }
    public override Vector2 DiedBodyOffset(){
        return diedBody.transform.localPosition;

    }
    public override Vector2 ForwardBodyOffset(){
        return forwardBody.transform.localPosition;

    }
    public override Vector2 ForwardProstrateBodyOffset(){
        return forwardProstrateBody.transform.localPosition;

    }
    public override Vector2 ElectricShockBodyOffset(){
        return electricShockBody.transform.localPosition;

    }
    public override Vector2 GoAheadBodyOffset(){
        return goAheadBody.transform.localPosition;
    }

    public override Vector2 UpperBodyPosition(){
        return upperBody.transform.position;
    }
    public override Vector2 LowerBodyPosition(){
        return lowerBody.transform.position;
    }
    public override Vector2 RollBodyPosition(){
        return rollBody.transform.position;
    }
    public override Vector2 FallBodyPosition(){
        return fallBody.transform.position;
    }
    public override Vector2 ProstrateBodyPosition(){
        return prostrateBody.transform.position;
    }
    public override Vector2 InWaterBodyPosition(){
        return inWaterBody.transform.position;
    }
    public override Vector2 RippleBodyPosition(){
        return rippleBody.transform.position;
    }
    public override Vector2 DiedBodyPosition(){
        return diedBody.transform.position;
    }
    public override Vector2 ForwardBodyPosition(){
        return forwardBody.transform.position;
    }
    public override Vector2 ForwardProstrateBodyPosition(){
        return forwardProstrateBody.transform.position;
    }
    public override Vector2 ElectricShockBodyPosition(){
        return electricShockBody.transform.position;
    }
    public override Vector2 GoAheadBodyPosition(){
        return goAheadBody.transform.position;
    }      

    // *↑↑↑↑↑↑↑↑↑↑↑↑↑↑以上是实现PlayerContext的方法↑↑↑↑↑↑↑↑↑↑↑↑↑↑

}
